using System;
using System.ComponentModel;
using System.Text;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ASPnetRater
{
    [ToolboxData("<{0}:Rater runat=\"server\"></{0}:Rater>")]
    public class Rater : WebControl, IPostBackEventHandler, INamingContainer
    {
        #region // Save/Load Control State
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            Page.RegisterRequiresControlState(this);
        }

        protected override object SaveControlState()
        {
            object[] objState = new object[1];
            objState[0] = _value;

            return objState;
        }

        protected override void LoadControlState(object state)
        {
            object[] savedState = (object[])state;
            _value = (int)savedState[0];

        }
        #endregion

        #region // PostBack Stuff
        private static readonly object EventCommand = new object();

        public event CommandEventHandler Command
        {
            add { Events.AddHandler(EventCommand, value); }
            remove { Events.RemoveHandler(EventCommand, value); }
        }

        protected virtual void OnCommand(CommandEventArgs e)
        {
            CommandEventHandler clickHandler = (CommandEventHandler)Events[EventCommand];
            if (clickHandler != null) clickHandler(this, e);
            base.RaiseBubbleEvent(this, e);
        }

        void IPostBackEventHandler.RaisePostBackEvent(string eventArgument)
        {
            Value = Convert.ToInt32(eventArgument);
            //OnCommand(new CommandEventArgs(this.UniqueID, Convert.ToInt32(eventArgument)));
            OnCommand(new CommandEventArgs(this.CommandName, Convert.ToInt32(eventArgument)));

        }
        #endregion

        #region // Accessors (Data)

        /// <summary>
        /// Gets or sets value of rater.
        /// </summary>
        private int _value = 0;
        [Category("Data")]
        public int Value
        {
            get { return _value; }
            set
            {
                _value = value;
            }
        }

        /// <summary>
        /// Gets or sets max value of rater.
        /// </summary>
        private int _maxValue = 5;
        [Category("Data")]
        public int MaxValue
        {
            get { return _maxValue; }
            set
            {
                _maxValue = value;
            }
        }

        /// <summary>
        /// Gets or sets: is the rater rated
        /// </summary>
        private bool _isRated = false;
        [Category("Data")]
        public bool IsRated
        {
            get { return _isRated; }
            set
            {
                _isRated = value;
            }
        }

        /// <summary>
        /// Gets or sets: is rating info shown
        /// </summary>
        private bool _showRatingInfo = true;
        [Category("Behavior")]
        public bool ShowRatingInfo
        {
            get { return _showRatingInfo; }
            set
            {
                _showRatingInfo = value;
            }
        }

        /// <summary>
        /// Gets or sets the text caption displayed as "Rating Info" in the rater.
        /// Default value: string.Empty;
        /// </summary>
        private string _ratingInfo = string.Empty;
        [Category("Data")]
        public string RatingInfo
        {
            get { return _ratingInfo; }
            set { _ratingInfo = value; }
        }

        /// <summary>
        /// Gets or sets command name of the rater.
        /// Default value: string.Empty;
        /// </summary>
        private string _commandName = string.Empty;
        [Category("Behavior")]
        public string CommandName
        {
            get { return _commandName; }
            set { _commandName = value; }
        }
        #endregion

        #region // Accessors (Appearance)
        /// <summary>
        /// Gets or sets image off of rater.
        /// Default value: string.Empty;
        /// </summary>
        private string _imageOff = string.Empty;
        [Category("Appearance")]
        public string ImageOff
        {
            get { return _imageOff; }
            set { _imageOff = ResolveUrl(value); }
        }

        /// <summary>
        /// Gets or sets image on of rater.
        /// Default value: string.Empty;
        /// </summary>
        private string _imageOn = string.Empty;
        [Category("Appearance")]
        public string ImageOn
        {
            get { return _imageOn; }
            set { _imageOn = ResolveUrl(value); }
        }

        /// <summary>
        /// Gets or sets image over of rater.
        /// Default value: string.Empty;
        /// </summary>
        private string _imageOver = string.Empty;
        [Category("Appearance")]
        public string ImageOver
        {
            get { return _imageOver; }
            set { _imageOver = ResolveUrl(value); }
        }

        /// <summary>
        /// Gets or sets the text caption displayed as "Rated Message" in the rater.
        /// Default value: "Thank You";
        /// </summary>
        private string _ratedMessage = "Thank You";
        [Category("Appearance")]
        public string RatedMessage
        {
            get { return _ratedMessage; }
            set { _ratedMessage = value; }
        }

        /// <summary>
        /// Gets or sets the css class of rater container.
        /// Default value: "RaterContainer";
        /// </summary>
        private string _cssClass_RaterContainer = "RaterContainer";
        [Category("Appearance")]
        public string CssClass_RaterContainer
        {
            get { return _cssClass_RaterContainer; }
            set { _cssClass_RaterContainer = value; }
        }

        /// <summary>
        /// Gets or sets the css class of rater item on.
        /// Default value: "RaterItemOn";
        /// </summary>
        private string _cssClass_RaterItemOn = "RaterItemOn";
        [Category("Appearance")]
        public string CssClass_RaterItemOn
        {
            get { return _cssClass_RaterItemOn; }
            set { _cssClass_RaterItemOn = value; }
        }

        /// <summary>
        /// Gets or sets the css class of rater item off.
        /// Default value: "RaterItemOff";
        /// </summary>
        private string _cssClass_RaterItemOff = "RaterItemOff";
        [Category("Appearance")]
        public string CssClass_RaterItemOff
        {
            get { return _cssClass_RaterItemOff; }
            set { _cssClass_RaterItemOff = value; }
        }

        /// <summary>
        /// Gets or sets the css class of rater item hover.
        /// Default value: "RaterItemHover";
        /// </summary>
        private string _cssClass_RaterItemHover = "RaterItemHover";
        [Category("Appearance")]
        public string CssClass_RaterItemHover
        {
            get { return _cssClass_RaterItemHover; }
            set { _cssClass_RaterItemHover = value; }
        }

        /// <summary>
        /// Gets or sets the css class of rater thank you.
        /// Default value: "RaterThankyou";
        /// </summary>
        private string _cssClass_RaterThankyou = "RaterThankyou";
        [Category("Appearance")]
        public string CssClass_RaterThankyou
        {
            get { return _cssClass_RaterThankyou; }
            set { _cssClass_RaterThankyou = value; }
        }

        /// <summary>
        /// Gets or sets the text caption displayed as "Rating Info" in the rater.
        /// Default value: "RatingInfo";
        /// </summary>
        private string _cssClass_RatingInfo = "RatingInfo";
        [Category("Globalization")]
        public string CssClass_RatingInfo
        {
            get { return _cssClass_RatingInfo; }
            set { _cssClass_RatingInfo = value; }
        }

        #endregion

        #region // Render Utilities
        //template of rater item
        private const string RaterItemTemplate =
                "<img id='{0}' border='0' style='border-style: none;' src='{1}'" +
                "\" onclick='{2}\"" +
                "' onmouseover='javascript:RatingHover(this)'" +
                "' onmouseoout='javascript:RatingRefresh(this)'" +
                "' />";

        //java script of onmouseover
        private string RenderHoverScript()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(
                    "function RatingHover(source) {" +
                        "var index = source.id.substring(source.id.lastIndexOf('_') + '_'.length, source.id.length);" +
                        "var IDParent = source.id.substring(0, source.id.lastIndexOf('_'));" +
                        "for (n = 1; n <= " + MaxValue.ToString() + "; n++)" +
                        "{" +
                            "if (n <= index)" +
                            "{" +
                                "document.getElementById(IDParent + '_' + n).src = '" + ImageOver + "';" +
                                "document.getElementById(IDParent + '_' + n).className = '" + _cssClass_RaterItemHover + "';" +
                            "}" +
                            "else" +
                            "{" +
                                "document.getElementById(IDParent + '_' + n).src = '" + ImageOff + "';" +
                                "document.getElementById(IDParent + '_' + n).className = '" + _cssClass_RaterItemOff + "';" +
                            "}" +
                        "}" +
                    "}"

                );

            string hoverScript = "<script type='text/javascript'>{0}</script>";

            return string.Format(hoverScript, sb.ToString());
        }

        //java script of onmouseoout
        private string RenderRefreshScript()
        {
            StringBuilder sb = new StringBuilder();

            sb.Append(
                    "function RatingRefresh(source) {" +
                        "var IDParent = source.id.substring(0, source.id.lastIndexOf('_'));" +
                        "var value = document.getElementById(IDParent + '_value').value;" +
                        "for (n = 1; n <= " + MaxValue.ToString() + "; n++)" +
                        "{" +
                            "if (n <= value)" +
                            "{" +
                                "document.getElementById(IDParent + '_' + n).src = '" + ImageOn + "';" +
                                "document.getElementById(IDParent + '_' + n).className = '" + _cssClass_RaterItemOn + "';" +
                            "}" +
                            "else" +
                            "{" +
                                "document.getElementById(IDParent + '_' + n).src = '" + ImageOff + "';" +
                                "document.getElementById(IDParent + '_' + n).className = '" + _cssClass_RaterItemOff + "';" +
                            "}" +
                        "}" +
                    "}"

                );

            string hoverScript = "<script type='text/javascript'>{0}</script>";

            return string.Format(hoverScript, sb.ToString());
        }

        //generate hidde field which hold current value of rater
        private string RenderHiddenValue()
        {
            return "<input id='" + UniqueID + "_value' type='hidden' value='" + Value.ToString() + "' />";
        }
        #endregion

        #region // Override Control's Render operation
        protected override void Render(HtmlTextWriter writer)
        {

            if (Page != null) Page.VerifyRenderingInServerForm(this);

            //check value and max value
            if (Value > MaxValue) throw new Exception("Rater: Value can not be greater than MaxValue");

            if (!IsRated)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, _cssClass_RaterContainer);
                writer.AddAttribute(HtmlTextWriterAttribute.Title, ToolTip);

                writer.RenderBeginTag(HtmlTextWriterTag.A);
                for (int i = 1; i <= MaxValue; i++)
                {
                    writer.AddAttribute(HtmlTextWriterAttribute.Id, UniqueID + "_" + i.ToString());
                    writer.AddAttribute(HtmlTextWriterAttribute.Style, "border-style: none;");

                    if (Enabled)
                    {
                        writer.AddAttribute(HtmlTextWriterAttribute.Onclick, Page.ClientScript.GetPostBackClientHyperlink(this, i.ToString()));
                        writer.AddAttribute("onmouseover", "javascript:RatingHover(this)");
                        writer.AddAttribute("onmouseout", "javascript:RatingRefresh(this)");
                    }

                    if (i <= Value)
                    {
                        writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass_RaterItemOn);
                        writer.AddAttribute(HtmlTextWriterAttribute.Src, ImageOn);
                    }
                    else
                    {
                        writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass_RaterItemOff);
                        writer.AddAttribute(HtmlTextWriterAttribute.Src, ImageOff);
                    }

                    writer.RenderBeginTag(HtmlTextWriterTag.Img);
                    writer.RenderEndTag();
                }

                writer.RenderEndTag();
                writer.Write(RenderHiddenValue());
                writer.Write(RenderHoverScript());
                writer.Write(RenderRefreshScript());
            }
            else
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass_RaterThankyou);
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.Write(RatedMessage);
                writer.RenderEndTag();
            }

            if (ShowRatingInfo)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, CssClass_RatingInfo);
                writer.RenderBeginTag(HtmlTextWriterTag.Div);
                writer.Write(RatingInfo);
                writer.RenderEndTag();
            }
        }


        #endregion
    }
}
